#ifndef FILE_ITERATOR_HPP_
#define FILE_ITERATOR_HPP_
#define NUM_PAGES (256*64)		//totally mapping 64MB
#define MAP_SIZE (NUM_PAGES * sysconf(_SC_PAGE_SIZE))	//mmap mult. page-size
//TODO
//consider FOPEN_MAX - maximum streams open for one process
//too bad if tmp files are to many, can't merge correctly

//used only for mapping, no guarantee for data consistency
//only mapped memory, watch class FileSorter to see how data consistency is
//achieved during sort(e.g. pages may intersect via one integer)
class FileIterator {
	private:
		int fd;
		unsigned int offset;
		unsigned int file_size;
		unsigned int mapped_size;
		unsigned int step_map_size;
		char *mapped_part;
	public:
		FileIterator(File& file) {
			fd = file.get_descriptor();
			offset = 0;
			file_size = file.get_size();
			mapped_size = 0;
			mapped_part = NULL;
			step_map_size = (unsigned int)MAP_SIZE;
			while ((file_size / step_map_size) > FOPEN_MAX) {
				step_map_size *= 2;	//increase mapping size
			}
		};
		//method returns next mapped area, or NULL if mmap failed
		char *next() {
			if (mapped_part != NULL) {
				int status = munmap(mapped_part, mapped_size);
				if (status == -1) {
					perror("problems with mapping next");
				}
			}
			mapped_size = std::min((long int)(file_size - offset), (long int)step_map_size);
			mapped_part = (char*)mmap(NULL, mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset);
			if (mapped_part == MAP_FAILED) {
				return NULL;
			}
			offset += mapped_size;
			return mapped_part;
		}
		char *get_content() {
			return mapped_part;
		}
		unsigned int get_mapped_size() {
			return mapped_size;
		}
		bool has_next() {
			return ((file_size - offset) > 0);
		}
		~FileIterator() {
			if (mapped_part != NULL) {
				int status = munmap(mapped_part, mapped_size);
				if (status == -1) {
					perror("problems with mapping next");
				}	
			}
		}
};
#endif